import aiofiles
from gsuid_core.sv import SV
from gsuid_core.bot import Bot
from gsuid_core.models import Event
import asyncio
from gsuid_core.logger import logger
import datetime
from typing import Optional
from sqlmodel import Field
from gsuid_core.aps import scheduler
from gsuid_core.gss import gss
from gsuid_core.utils.image.convert import convert_img
from gsuid_core.data_store import image_res
from PIL import Image
import os
import asyncio
from curl_cffi import AsyncSession
import aiofiles
import httpx


# from gsuid_core.utils.database.base_models import Bind, User

# class ListenBind(Bind, table=True):
#     # 注意，这里的列名无需新增id等基类已经有的列，只需要根据自己实际需求新增列名即可
#     # 具体基类有什么列可以点进Bind类去查看
#     uid: Optional[str] = Field(default=None, title='=服务监听')



GET_KEY = True
GET_RESULT_KEY = False
TIME_RESULT = True
TODAY_DATETIME = datetime.datetime.now().strftime("%m-%d")
weather_warnings = []
gs_weather_info = SV('天气信息查询')



def get_price():
    """
    获取实时价格
    """
    from curl_cffi import requests
    import re
    url = "https://mobile.cmbchina.com/igoldaccount/golddetail/price-diff"
#     headers = {
#     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0",
#     "Accept": "application/json",
#     "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
#     "Connection": "keep-alive",
#     "Cookie": "MFE_MSID2=63b986454d714b218d54b8bafa235130",
#     "Upgrade-Insecure-Requests": "1",
#     "Sec-Fetch-Dest": "document",
#     "Sec-Fetch-Mode": "navigate",
#     "Sec-Fetch-Site": "none",
#     "Sec-Fetch-User": "?1",
#     "Priority": "u=0, i",
#     "Content-Type": "application/json",
#     "Content-type": "application/json"
#   }

    response = requests.get(url, impersonate="chrome")
    if response.status_code != 200:
        logger.info(response.status_code)
        return None
    else:
        json_text = response.text
        logger.info(json_text)
        buyPrice = re.findall(r'(?<=buyPrice":")\d{0,3}\.\d{0,2}', json_text)[0]
        sellPrice = re.findall(r'(?<=sellPrice":")\d{0,3}\.\d{0,2}', json_text)[0]
        # logger.info(buyPrice)
        # logger.info(sellPrice)
        return f'购买：{buyPrice}, 出售：{sellPrice}'


def get_workingDayResult():
    """
    获取工作日详情
    """
    global GET_RESULT_KEY, TIME_RESULT
    GET_RESULT_KEY = True
    url = "http://api.haoshenqi.top/holiday/today"
    import requests
    response = requests.get(url)
    if response.text == '工作':
        TIME_RESULT = True
        return True
    else:
        TIME_RESULT = False
        return False


@gs_weather_info.on_command(('金价'), block=True)
async def send_GoldPrice_msg(bot: Bot, ev: Event):
    global GET_KEY, GET_RESULT_KEY, TIME_RESULT, TODAY_DATETIME
    # 先获取当前是否开市 --工作日9-24
    # GET_RESULT_KEY
    GET_KEY = True
    now_date = datetime.datetime.now().strftime("%m-%d")
    if TODAY_DATETIME != now_date:
        GET_RESULT_KEY = False
        TIME_RESULT =  True
        TODAY_DATETIME = now_date
    if not GET_RESULT_KEY:
        get_workingDayResult()
    if GET_RESULT_KEY and not TIME_RESULT:
        await bot.send("当前非工作日，取消获取")
    else:
        if int(datetime.datetime.now().strftime("%H")) in range(9, 24):
            # 全部检验通过后 开始获取
            while True and int(datetime.datetime.now().strftime("%H")) in range(9, 24):
                if GET_KEY:
                    await bot.send(get_price())
                    await asyncio.sleep(15)
                else:
                    break
            else:
                await bot.send("已收盘")
        else:
            await bot.send("当前非开市时间，取消获取")


@gs_weather_info.on_command(('停止金价'), block=True)
async def STOP_send_msg(bot: Bot, ev: Event):
    global GET_KEY
    GET_KEY = False
    await bot.send('已停止获取金价')


@gs_weather_info.on_command(('ssh'), block=True)
async def GetSshIpPort(bot: Bot, ev: Event):
    """
    获取sship
    """
    from curl_cffi import requests

    getTokenUrl = "http://localhost:9200/api/v1/user/login"

    payload = {
        "email": "jia.2778@foxmail.com",
        "password": "Hao.1234"
    }
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:132.0) Gecko/20100101 Firefox/132.0",
        "Accept": "application/json, text/plain, */*",
        "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
        "Accept-Encoding": "gzip, deflate, br, zstd",
        "Content-Type": "application/json;charset=utf-8",
        "Connection": "keep-alive",
        "Sec-Fetch-Dest": "empty",
        "Sec-Fetch-Mode": "cors",
        "Sec-Fetch-Site": "same-origin",
        "Priority": "u=0"
    }
    try:
        getTokenResponse = requests.request("POST", getTokenUrl, json=payload, headers=headers)
        token = getTokenResponse.json()['data']['token']
        getTunnrlUrl = "http://localhost:9200/api/v1/tunnels"
        authHeaders = {
            "Authorization": f"Bearer {token}",
            "Cookie": f"vue_admin_template_token={token}",
        }
        getTunnrlHeaders = {**headers, **authHeaders}
        try:
            getTunnrlResponse = requests.request("GET", getTunnrlUrl, headers=getTunnrlHeaders)
            tunnrls = list(getTunnrlResponse.json()['data']['items'])
            for tunnrl in tunnrls:
                if tunnrl['name'] == 'ssh':
                    await bot.send(str(tunnrl['public_url']))
                    break
            else:
                await bot.send('未找到ssh项')
        except Exception as sshe:
            await bot.send('ssh获取出错')
            raise sshe
    except Exception as e:
        await bot.send("token获取出错")
        await bot.send(str(e))


# @gs_weather_info.on_prefix(('ds'), block=True)
# async def qwen_chat(bot: Bot, ev: Event):
#     """
#     连接deepseek
#     """
#     from ollama import Client
#     client = Client(
#     host='http://192.168.88.1:11434',
#     headers={'x-some-header': 'some-value'}
#     )
#     response = client.chat(model='deepseek-r1:14b', messages=[
#     {
#         'role': 'user',
#         'content': f'{ev.text}',
#     },
#     ])
#     print(response)
#     print(response['message'])
#     await bot.send(response['message']['content'].split('>')[-1].strip())


@gs_weather_info.on_command(('uid'), block=True)
async def GetSshIpPort(bot: Bot, ev: Event):
    from curl_cffi import requests

    getTokenUrl = "http://localhost:9200/api/v1/user/login"

    payload = {
        "email": "jia.2778@foxmail.com",
        "password": "Hao.1234"
    }
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:132.0) Gecko/20100101 Firefox/132.0",
        "Accept": "application/json, text/plain, */*",
        "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
        "Accept-Encoding": "gzip, deflate, br, zstd",
        "Content-Type": "application/json;charset=utf-8",
        "Connection": "keep-alive",
        "Sec-Fetch-Dest": "empty",
        "Sec-Fetch-Mode": "cors",
        "Sec-Fetch-Site": "same-origin",
        "Priority": "u=0"
    }
    try:
        getTokenResponse = requests.request("POST", getTokenUrl, json=payload, headers=headers)
        token = getTokenResponse.json()['data']['token']
        getTunnrlUrl = "http://localhost:9200/api/v1/tunnels"
        authHeaders = {
            "Authorization": f"Bearer {token}",
            "Cookie": f"vue_admin_template_token={token}",
        }
        getTunnrlHeaders = {**headers, **authHeaders}
        try:
            getTunnrlResponse = requests.request("GET", getTunnrlUrl, headers=getTunnrlHeaders)
            tunnrls = list(getTunnrlResponse.json()['data']['items'])
            for tunnrl in tunnrls:
                if tunnrl['name'] == 'uid':
                    await bot.send("gscore 登录地址为：" + str(tunnrl['public_url'] + "/genshinuid"))
                    await bot.send("astrbot 登录地址为：" + str(tunnrl['public_url']))
                    # return Get_Uri(str(tunnrl['public_url']))
                    break
            else:
                await bot.send('未找到uid项')
        except Exception as sshe:
            await bot.send('url获取出错')
            await bot.send(str(sshe))
    except Exception as e:
        await bot.send("url获取出错")
        await bot.send(str(e))


async def get_image():
    """
    从指定API下载摸鱼日历图片

    Returns:
        PIL.Image | str: 成功返回Image对象，失败返回错误信息
    """
    url = "https://api.vvhan.com/api/moyu"

    # 确保保存目录存在
    os.makedirs(image_res, exist_ok=True)

    async with httpx.AsyncClient(timeout=httpx.Timeout(200.0)) as session:
        try:
            # 获取图片真实链接
            resp = await session.get(url)
            logger.info(f"获取图片链接: {resp.headers}")
            real_link = resp.headers['location']
            file_name = real_link.split('/')[-1]
            file_path = os.path.join(image_res, file_name)

            # 下载图片
            logger.info(f"开始下载图片: {real_link}")

            res = await session.get(real_link)
            content = res.read()
            retcode = res.status_code

            if retcode == 200:
                async with aiofiles.open(file_path, "wb") as f:
                    await f.write(content)
                logger.success(f'moyu下载完成！')
            else:
                logger.warning(f"moyu 下载失败！错误码{retcode}")
                return f"moyu 下载失败！错误码{retcode}"
            try:
                with Image.open(file_path) as img:
                    img.verify()
            except Exception as e:
                logger.error(f"图片验证失败：{e}")
                if os.path.exists(file_path):
                    os.remove(file_path)
                return f"图片验证失败：{e}"
            return Image.open(file_path)

        except KeyError as e:
            logger.error(f"获取图片链接失败：headers中没有location字段 - {e}")
            return f"获取图片链接失败：{e}"
        except (IOError, OSError) as e:
            logger.error(f"文件操作失败：{e}")
            return f"文件操作失败：{e}"
        except Exception as e:
            logger.error(f"未知错误：{e}")
            return f"未知错误：{e}"


@scheduler.scheduled_job('cron', hour=9, minute='30')
# @scheduler.scheduled_job('cron', minute='*/1')
async def moyu():
    for _ in range(9):  # 重试9次
        im = await get_image()  # 自己的业务逻辑
        if isinstance(im, Image.Image):
            for BOT_ID in gss.active_bot:  # 获取全部连接中的Bot，注意，这里的BOT_ID和bot_id并不等价
                bot = gss.active_bot[BOT_ID]  # 拿到bot实例
                await bot.target_send(
                    await convert_img(im),  # 具体要发送的消息
                    'group',  # 发送方式group或者direct
                    "43524836881@chatroom",  # 发送目标，群号或者用户id，str
                    "wechatpadpro",  # 实际bot_id、和上面的BOT_id不同，例如onebot等等
                    "wxid_50jdxtbogyml22",
                    "",
                    "",
                    ""
                )
                # 43015699870 @ chatroom
                await bot.target_send(
                    await convert_img(im),  # 具体要发送的消息
                    'group',  # 发送方式group或者direct
                    "43015699870@chatroom",  # 发送目标，群号或者用户id，str
                    "wechatpadpro",  # 实际bot_id、和上面的BOT_id不同，例如onebot等等
                    "wxid_50jdxtbogyml22",
                    "",
                    "",
                    ""
                )
                await bot.target_send(
                    await convert_img(im),  # 具体要发送的消息
                    'group',  # 发送方式group或者direct
                    "25069168054@chatroom",  # 发送目标，群号或者用户id，str
                    "wechatpadpro",  # 实际bot_id、和上面的BOT_id不同，例如onebot等等
                    "wxid_50jdxtbogyml22",
                    "",
                    "",
                    ""
                )
            break
        else:
            for BOT_ID in gss.active_bot:  # 获取全部连接中的Bot，注意，这里的BOT_ID和bot_id并不等价
                bot = gss.active_bot[BOT_ID]
                await bot.target_send(
                    str(im),
                    "direct",
                    "wxid_ien4gms402y722",
                    "wechatpadpro",
                    "wxid_50jdxtbogyml22",
                    "",
                    "",
                    ""
                )
                await bot.target_send(
                    f"等待10秒后进行第 {_ + 1} 次重试",
                    "direct",
                    "wxid_ien4gms402y722",
                    "wechatpadpro",
                    "wxid_50jdxtbogyml22",
                    "",
                    "",
                    ""
                )
            await asyncio.sleep(10)

    else:
        def get_current_weekday():
            """获取今日周几"""
            today = datetime.datetime.now()
            # weekday() 返回0-6对应周一到周日
            weekdays = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
            str_today = today.strftime("%Y年-%m月-%d日")
            return f"图片获取失败 今天是 {str_today} {weekdays[today.weekday()] - 1}"

        for BOT_ID in gss.active_bot:  # 获取全部连接中的Bot，注意，这里的BOT_ID和bot_id并不等价
            bot = gss.active_bot[BOT_ID]  # 拿到bot实例
            await bot.target_send(
                get_current_weekday() + f"  失败原因 {str(im)}",  # 具体要发送的消息
                'group',  # 发送方式group或者direct
                "43524836881@chatroom",  # 发送目标，群号或者用户id，str
                "wechatpadpro",  # 实际bot_id、和上面的BOT_id不同，例如onebot等等
                "wxid_50jdxtbogyml22",
                "",
                "",
                ""
            )
            # 43015699870 @ chatroom
            await bot.target_send(
                get_current_weekday() + f"  失败原因 {str(im)}",  # 具体要发送的消息
                'group',  # 发送方式group或者direct
                "43015699870@chatroom",  # 发送目标，群号或者用户id，str
                "wechatpadpro",  # 实际bot_id、和上面的BOT_id不同，例如onebot等等
                "wxid_50jdxtbogyml22",
                "",
                "",
                ""
            )
            await bot.target_send(
                get_current_weekday() + f"  失败原因 {str(im)}",  # 具体要发送的消息
                'group',  # 发送方式group或者direct
                "25069168054@chatroom",  # 发送目标，群号或者用户id，str
                "wechatpadpro",  # 实际bot_id、和上面的BOT_id不同，例如onebot等等
                "wxid_50jdxtbogyml22",
                "",
                "",
                ""
            )


def base64url_encode():
    """
    进行base64url编码
    """
    import sys
    import time
    import jwt
    from cryptography.hazmat.primitives import serialization
    from pathlib import Path

    # Open PEM
    with open(Path.home() / "ed25519-private.pem", "rb") as f:
        private_key = serialization.load_pem_private_key(
            f.read(),
            password=None  # 如果有密码，传入bytes
        )
    # private_key = "MC4CAQAwBQYDK2VwBCIEIKG1ss4BJiXw0y0FG2QViA+XpuT1hN92MJE4WzLCEaxn"

    payload = {
        'iat': int(time.time()) - 30,
        'exp': int(time.time()) + 900,
        'sub': '4F87KRPU36'
    }
    headers = {
        'kid': 'TJGUJ227RN'
    }

    # Generate JWT
    encoded_jwt = jwt.encode(payload, private_key, algorithm='EdDSA', headers=headers)

    return encoded_jwt


async def fetch_weather_data(warning=False, hours=False):
    if warning:
        url = "https://mx5ctu9cdd.re.qweatherapi.com/v7/warning/now?location=116.28,40.05"
    elif hours:
        url = "https://mx5ctu9cdd.re.qweatherapi.com/v7/weather/24h?location=116.28,40.05"
    else:
        url = "https://mx5ctu9cdd.re.qweatherapi.com/v7/weather/now?location=116.28,40.05"
    token = base64url_encode()

    headers = {
        "Authorization": f"Bearer {token}",
        "Accept-Encoding": "gzip, deflate, br"
    }

    async with httpx.AsyncClient(
        timeout=30.0,  # 设置超时时间
        follow_redirects=True  # 自动跟随重定向
    ) as client:
        try:
            response = await client.get(url, headers=headers)
            # 返回响应数据
            logger.info(response.json())
            return response.json()

        except httpx.HTTPStatusError as e:
            logger.error(f"HTTP 错误: {e.response.status_code} 错误内容： e.response.text if e.response else \"无响应内容\"")
            return f"HTTP 错误: {e.response.status_code} 错误内容： e.response.text if e.response else \"无响应内容\"",
        except httpx.RequestError as e:
            logger.error(f"请求错误: {str(e)}")
            return  f"请求错误: {str(e)}"
        except Exception as e:
            logger.error(f"其他错误: {str(e)}")
            return f"其他错误: {str(e)}"


@scheduler.scheduled_job('cron', hour='10-20', minute='*/10')
async def send_weather_warnings():
    """
    定时发送天气预警信息
    """
    weather_data = await fetch_weather_data(True,False)
    if "错误" in weather_data:
        for BOT_ID in gss.active_bot:  # 获取全部连接中的Bot，注意，这里的BOT_ID和bot_id并不等价
            bot = gss.active_bot[BOT_ID]
            await bot.target_send(
                        weather_data,
                        "direct",
                        "wxid_ien4gms402y722",
                        "wechatpadpro",
                        "wxid_50jdxtbogyml22",
                        "",
                        "",
                        ""
                    )
    else:
        warnings_data = weather_data['warning']
        global weather_warnings
        for warning in warnings_data:
            if warning['id'] not in weather_warnings:
                weather_warnings.append(warning['id'])
                for BOT_ID in gss.active_bot:
                    bot = gss.active_bot[BOT_ID]
                    await bot.target_send(
                        warning['text'],  # 具体要发送的消息
                        'group',  # 发送方式group或者direct
                        "43015699870@chatroom",  # 发送目标，群号或者用户id，str
                        "wechatpadpro",  # 实际bot_id、和上面的BOT_id不同，例如onebot等等
                        "wxid_50jdxtbogyml22",
                        "",
                        "",
                        ""
                    )


@scheduler.scheduled_job('cron', hour='8', minute='50')
# @scheduler.scheduled_job('cron', minute='*/1')
async def send_weather_hours():
    """
    定时发送天气预警信息
    """
    weather_data = await fetch_weather_data(False,True)
    if "错误" in weather_data:
        for BOT_ID in gss.active_bot:  # 获取全部连接中的Bot，注意，这里的BOT_ID和bot_id并不等价
            bot = gss.active_bot[BOT_ID]
            await bot.target_send(
                        weather_data,
                        "direct",
                        "wxid_ien4gms402y722",
                        "wechatpadpro",
                        "wxid_50jdxtbogyml22",
                        "",
                        "",
                        ""
                    )
    else:
        warnings_data = weather_data['hourly'][:12]
        weather_text = get_weather_info_hours(warnings_data)
        for BOT_ID in gss.active_bot:
            bot = gss.active_bot[BOT_ID]
            await bot.target_send(
                weather_text,  # 具体要发送的消息
                'group',  # 发送方式group或者direct
                "43015699870@chatroom",  # 发送目标，群号或者用户id，str
                "wechatpadpro",  # 实际bot_id、和上面的BOT_id不同，例如onebot等等
                "wxid_50jdxtbogyml22",
                "",
                "",
                ""
            )

def get_weather_info(weather_data):
    """
    解析天气信息
    """
    weather_info = weather_data['now']
    text = f"实时天气：{weather_info['text']}\n"
    temp = f"温度：{weather_info['temp']}℃\n"
    wind_dir = f"风向：{weather_info['windDir']}\n"
    wind_scale = f"风力：{weather_info['windScale']}\n"
    return text + temp + wind_dir + wind_scale

def get_weather_info_hours(weather_data):
    """
    解析天气信息
    """
    info_text = ""

    def get_hours(fxTime):
        """
        获取小时
        """
        return fxTime.split("T")[1].split(':')[0]

    for weather_info in weather_data:
        info_text += f"{get_hours(weather_info['fxTime'])}时 {weather_info['text']} {weather_info['windDir']} {weather_info['windScale']}级\n"
    return info_text



@gs_weather_info.on_command('天气', block=True)
async def send_weather_info_now(bot: Bot, ev: Event):
    """
    触发实时天气
    """
    weather_data = await fetch_weather_data()
    if "错误" in weather_data:
        await bot.send(f"实时天气获取失败。{weather_data}")
    else:
        await bot.send(get_weather_info(weather_data))
